package com.ifd.controller;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextArea;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;

import org.apache.log4j.Logger;

import com.ibm.as400.access.AS400;
import com.ibm.as400.access.IFSFile;
import com.ibm.as400.access.IFSFileInputStream;
import com.ibm.as400.access.ProgramCall;
import com.ibm.as400.access.QSYSObjectPathName;
import com.ibm.as400.access.SpooledFile;
import com.ifd.as400.IFDConnectionPool;
import com.ifd.as400.IFDException;
import com.ifd.core.api.GenAS400Function;
import com.ifd.gui.JSwingPad;

public class SpoolDataController implements CaretListener {
	static final Logger logger = Logger.getLogger(SpoolDataController.class);
	private boolean isUpdated = false;
	private boolean isLoaded = false;
	private String pcFile = null;
	private String spName = null;
	private JTextArea textArea;
	private SplfDefaultProperties defaultProp;
	private float pageWidth, pageLength;
	private JSwingPad owner;

	public SpoolDataController(JSwingPad owner) throws IFDException {
		this.textArea = (JTextArea) owner.getComponentManager()
				.get("text_area");
		this.textArea.addCaretListener(this);
		defaultProp = new SplfDefaultProperties();
		pageWidth = Float.parseFloat(defaultProp.getProperty("PAGE_WIDTH"));
		pageLength = Float.parseFloat(defaultProp.getProperty("PAGE_LENGTH"));
		this.owner = owner;
	}
	
	public void resetTextArea(){
		((JTextArea) owner.getComponentManager().get("text_area")).setText("");
	}
	/**
	 * Load data from an offline spool file in PC
	 * 
	 * @param pcFile
	 */
	public void loadData(String pcFile) throws IFDException {
		File file;
		if(pcFile.trim().length()<=0){
			JFileChooser fc = new JFileChooser();
			fc.setMultiSelectionEnabled(false);
			if(fc.showOpenDialog(owner)!=JFileChooser.OPEN_DIALOG)
				return;
			file=fc.getSelectedFile();
		}else{
			file = new File(pcFile);
			if(!file.exists())
				return;
		}	
		try {
			BufferedReader in = new BufferedReader(new FileReader(file));
			this.pcFile = pcFile;
			spName = file.getName();
			textArea.read(in, file);
			pageWidth = Float.parseFloat(defaultProp.getProperty("PAGE_WIDTH"));
			pageLength = Float.parseFloat(defaultProp.getProperty("PAGE_LENGTH"));
			isLoaded = true;
		} catch (Exception e) {
			throw new IFDException(e.getLocalizedMessage(), logger);
		}
	}

	public void loadData(SpooledFile splf) throws IFDException {
		QSYSObjectPathName outq;
		try {
			pageWidth = splf.getFloatAttribute(SpooledFile.ATTR_PAGEWIDTH);
			pageLength = splf.getFloatAttribute(SpooledFile.ATTR_PAGELEN);
			defaultProp.setProperty("PAGE_WIDTH", ""+pageWidth);
			defaultProp.setProperty("PAGE_LENGTH", ""+pageLength);
			outq = new QSYSObjectPathName(
					splf.getSingleStringAttribute(SpooledFile.ATTR_OUTPUT_QUEUE));
		} catch (Exception e) {
			throw new IFDException(e.getLocalizedMessage(), logger);
		}
		AS400 as400 = IFDConnectionPool.getAS400();
		ProgramCall pgm = new ProgramCall(as400);
		GenAS400Function.qcmdexc(pgm, "ADDLIBLE QTEMP");

		// Copy spool file to physical file in QTEMP
		GenAS400Function.qcmdexc(pgm, "CRTPF FILE(QTEMP/SPLF) RCDLEN("
				+ (int) pageWidth + ") SIZE(*NOMAX)", logger);
		String command = "CPYSPLF FILE(" + splf.getName()
				+ ") TOFILE(QTEMP/SPLF) JOB(" + splf.getJobNumber() + "/"
				+ splf.getJobUser().trim() + "/" + splf.getJobName()
				+ ") SPLNBR(" + splf.getNumber() + ") CTLCHAR(*PRTCTL)";
		GenAS400Function.qcmdexc(pgm, command, logger);

		// Create temp. dir
		GenAS400Function.qcmdexc(pgm, "CRTDIR DIR('/HOME/" + as400.getUserId()
				+ "')");
		// Copy physical file to IFS '/HOME/<USER NAME>'
		spName = splf.getName().trim() + "-" + outq.getObjectName().trim() + "-"
				+ outq.getLibraryName().trim() + ".txt";
		String ifsFile = "/HOME/" + as400.getUserId() + "/" + spName;
		command = "CPYTOSTMF FROMMBR('/QSYS.LIB/QTEMP.LIB/SPLF.FILE/SPLF.MBR') "
				+ "TOSTMF('"
				+ ifsFile
				+ "') STMFOPT(*REPLACE) CVTDTA(*TBL) DBFCCSID(37) "
				+ "STMFCODPAG(37) TBL('/QSYS.LIB/QASCII.TBL') ENDLINFMT(*CRLF)";
		GenAS400Function.qcmdexc(pgm, command, logger);

		parsePRTCTLtoPlain(ifsFile, textArea);
		IFSFile file = new IFSFile(IFDConnectionPool.getAS400(),ifsFile);
		try {
			file.delete();
		} catch (Exception e) {
		}
		isLoaded = true;
	}

	/**
	 * Display spool data to JTextArea
	 */
	public void show() {
		if (!isLoaded)
			return;
	}

	public boolean isUpdated() {
		return isUpdated;
	}

	/**
	 * Parse IFS file with *PRTCTL format to Windows
	 * 
	 * @param ifsFile
	 * @param pcFile
	 */
	private void parsePRTCTLtoPlain(String ifsFile, JTextArea txt)
			throws IFDException {
		IFSFileInputStream is = null;
		BufferedReader reader = null;
		txt.setText("");
		try {
			is = new IFSFileInputStream(IFDConnectionPool.getAS400(), ifsFile);
			reader = new BufferedReader(new InputStreamReader(is));
			String line = reader.readLine();
			int curLineNum = 1;
			int lineNum = 0;
			int skipBef = 0, spaceBef = 0;
			while (line != null) {
				String skip = line.substring(0, 3);
				String space = line.substring(3, 4);
				if (skip.trim().length() > 0) {
					skipBef = Integer.parseInt(skip);
					lineNum = skipBef;
				}
				if (space.trim().length() > 0) {
					spaceBef = Integer.parseInt(space);
					lineNum += spaceBef;
				} else
					spaceBef = 0;

				if (lineNum < curLineNum) // New page
				{
					for (int i = curLineNum; i <= pageLength; i++, curLineNum++)
						txt.append("\n");
					curLineNum = 1;
				}

				if (skip.trim().length() > 0) {
					for (; curLineNum < skipBef; curLineNum++)
						txt.append("\n");
					txt.append(line.substring(4));
				}
				if (space.trim().length() > 0) {
					for (int i = 0; i < spaceBef; i++, curLineNum++)
						txt.append("\n");
					txt.append(line.substring(4));
				}

				curLineNum = lineNum;
				line = reader.readLine();
			}
		} catch (Exception e) {
			throw new IFDException(e.getLocalizedMessage(), logger, e);
		} finally {
			try {
				if (is != null)
					is.close();
			} catch (Exception e2) {
			}
			try {
				if (reader != null)
					reader.close();
			} catch (Exception e2) {
			}
		}

	}

	public void caretUpdate(CaretEvent e) {
		try {
			int line, column;
			int caretpos = textArea.getCaretPosition();
			line = textArea.getLineOfOffset(caretpos);
			column = caretpos - textArea.getLineStartOffset(line);
			updateCursorPosition(line, column);
		} catch (Exception e2) {
		}
	}

	public boolean saveData() throws IFDException {
		if(spName==null || spName.trim().length()<=0)
			spName="MySpoolFile.txt";
		File file=new File(spName);
		JFileChooser fc = new JFileChooser(file);
		fc.setSelectedFile(file);
		if(fc.showSaveDialog(owner)!=JFileChooser.APPROVE_OPTION)
			return true;
		file = fc.getSelectedFile();
		if (file == null)
			return false;
		if(file.exists() &&
			JOptionPane.showConfirmDialog(null, "File " + spName + " exist already. " +
					"Do you want to overwrite?", 
					"SpoolFile Editor", JOptionPane.YES_NO_OPTION)== JOptionPane.NO_OPTION)
			return false;

		FileOutputStream os = null;
		OutputStreamWriter writer = null;
		try {
			os = new FileOutputStream(file);
			writer = new OutputStreamWriter(os);
			textArea.write(writer);
		} catch (Exception e) {
			throw new IFDException(e.getLocalizedMessage(), logger);
		} finally {
			if (writer != null)
				try {
					writer.close();
				} catch (Exception e2) {
				}
		}
		return true;
	}

	private void updateCursorPosition(int line, int column) {
		JLabel position = (JLabel) owner.getComponentManager().get(
				"status_position");
		JLabel page = (JLabel) owner.getComponentManager().get("status_page");
		int pageNum = (int) line / (int) pageLength + 1;
		page.setText("Page " + pageNum);
		int spoolLine, spoolColumn;
		spoolColumn = column + 1;
		spoolLine = line % (int) pageLength + 1;
		position.setText(spoolLine + " : " + spoolColumn);

	}

}
